/*
clsquare - closed loop simulation system
Copyright (c) 2004, Neuroinformatics Group, Prof. Dr. Martin Riedmiller,
University of Osnabrueck

Author: Stephan Timmer

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.
   * Neither the name of the <ORGANIZATION> nor the names of its
     contributors may be used to endorse or promote products derived
     from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#ifndef _CMAC_H_
#define _CMAC_H_

#define MAX_STR_LEN 255

#include "setdef.h"
#include <vector>
#include <set>
#include <fstream>
#include <iostream>
  
class Cmac;

/** Implements a tiling of a CMAC function approximator. */
class Tiling {  
 public:

  /** pointer to Cmac which is the container of this tiling. */
  Cmac* cmac;
  
  /** dimension of input space */
  unsigned int dimension;
  
  /** size of tiling (number of tiles) */
  int size;
  
  /** additional space for tilings (in every dimension). 
   * extra Space that is added to the input space in every dimension  */
  vector<double> tilingExtend;

  /** size of tiling: input space + extend. */
  vector<double> totalTilingSize;
  
  /** offset by which tiling is displaced relative to the 
      input space (in every dimension) */
  vector<double> offset;
  
  /** formal resolution of complete (plus extend) tiling in every dimension */
  vector<int> resolution;
  
  /** (real) resolution of tiling within input space.
   *  Example: If there are x tiles in a tiling with respect to the 
   *  formal resolution above, the inputResolution is the resolution which
   *  gives x tiles for the input space. Outside the input, nothing has to be
   * stored. */
  vector<int> inputResolution;

  /** reference Point needed to compute the origin of the input space within a complete tiling. */
  vector<double> refPoint;

  /** fraction constant needed to compute the origin of the input space within a complete tiling. */
  vector<double> fraction; 
  
  /** Origin of input space in tiling (in number of tiles) */
  vector<int> inputOrigin;
  
  /** helps to map from multidimensional (discrete) coordinates of tiles to a single integer.
   * Needed to compute an index for accessing the weights of the tiles. */
  vector<int> tilesMult; 
  
  /** multidimensional array of tiles (weights of receptive fields)*/
  double* tiles;  
  
  /** initial value of weigths */
  double initialValue;
   
                        
  /** parse a vector of doubles from string. 
   * \param vec: resulting vector 
   * \param param: string which contains information */  
  void parseVector(vector<double> &vec, const char* param); 
  
  
  /** initializes the tiling given a standard resolution.
      Initializes weights and offsets of the tiling.
      \param cmac: parental cmac of this tiling    
      \param initialValue: initial value for weights of tiling. */
  Tiling(Cmac* cmac, double initialValue);
  
  /** initializes the tiling given a certain resolution.   
      \param cmac: parental cmac of this tiling
      \param tilingExtend: additional space of tiling in every dimension 
      \param resolution: resolution of complete tiling
      \param initialValue: initial value for weights of tiling. */
  Tiling(Cmac* cmac, vector<double> tilingExtend, vector<int> resolution, double initialValue);
  
  /** reinitializes the tiling given a certain resolution. 
      \param tilingExtend: additional space of tiling in every dimension 
      \param resolution: complete resolution of tiling 
      \param random: Random initilization of tiling displacement  */
  void init(vector<double> tilingExtend, vector<int> resolution, bool random);
  
  
  /** saves Tiling to a file. 
      \param file: Filestream */
  void save(std::fstream* file);
  
  /** loads tiling from a file.
      \param file: filestream     
      \result: true for success */   
  bool load(std::fstream* file);
  
  /** Removes memory of tiling. */
  ~Tiling();   
};

/** Implements the CMAC function approximator. All tilings were implemented as
 *  grids (hypercubes). Parameters of a tiling are the size of the space which
 *  is added to the input space and the formal resolution of the tiling.
 *  The formal resolution of a tiling is given with respect to the complete tiling 
 *  (input space + extend). Internally a slightly different resolution is used:
 *  The actually used resolution for the input space implies the same number of tiles 
 * (within input space) than the formal resolution would do for the complete tiling.
    \author Stephan Timmer */
class Cmac {
 private:     
  /** definition of input space (in every dimension) */
  SetDef inputSpace;
  
  /** Dimension of input space */
  unsigned int dimension;
     
  /** vector of tilings. */
  vector<Tiling*> tilings; 
  
  /** learning rate of gradient descent */
  double learningRate;           
 
  /** testing purposes. */
  double computeTestFunction(double x,double y);
  
 public: 
  /** constructs a CMAC-Approximator
      \param inputSpace: definition of input space    
      \param learningRate: learning_rate for gradient descent */  
  Cmac(SetDef inputSpace, double learningRate);
  
  /** adds a tiling to set of tilings.
      \param tilingExtend: additional space of tiling in every dimension
      \param resolution: formal resolution of tiling (in every dimension) 
      \param initialValue: initial value of weights of tiling */   
  void addTiling(vector<double> tilingExtend, vector<int> resolution, double initialValue);
  
  /** gets approximated value for a certain point in input space.
      \param point: point in input space
      \result: value of this point */
  double getValue(vector<double> point);
  
  /** performs an update of the approximation of a certain point in input space
      \param point: certain point in input space
      \param newValue: new value to be stored for this point */
  void setValue(vector<double> point, double newValue);          
  
  /** gets the input space */
  SetDef getInputSpace();
  
  /** saves CMAC to a file. 
      \param fileName: Name of file */
  void save(char* fileName);
  
  /** loads CMAC from file.
      \param fileName: name of file
      \param dim: dimension of input space
      \result: true for success */      
  bool load(char* fileName, int dim);

  /** Testing purposes. */
  void test();
  
  /** destructs the CMAC */
  ~Cmac();
  
};

#endif
